package com.example.waterdispenserm2.mo.gpio;




import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class GpioSerialProtocolHelper {

        private static final String TAG = "SerialProtocol";
        private static final int DATA_PIN = 1; // 使用IO1作为数据线
        private static final String GPIO_BASE = "/sys/class/gpio";
        private static final long BIT_DELAY = 750; // 单位：微秒 (1位=750μs)

        // 协议常量
        private static final byte LEADER_CODE_DURATION = 2; // 引导码时长(ms)
        private static final byte IDENTIFICATION_CODE = (byte) 0xA5;
        private static final int PACKET_SIZE = 8; // 主机数据包长度(1引导+6数据+1校验)

        private volatile boolean isRunning = false;
        private OnDataReceivedListener listener;
        private Thread receiveThread;

        public interface OnDataReceivedListener {
            void onDisplayData(byte[] displayData); // 显示数据回调
            void onSendComplete(); // 发送完成回调
            void onLogMessage(String message); // 日志消息回调
        }

        public GpioSerialProtocolHelper(OnDataReceivedListener listener) {
            this.listener = listener;
            initGPIO();
        }

        // 初始化GPIO
        private void initGPIO() {
            try {
                exportGPIO(DATA_PIN);
                setGPIODirection(DATA_PIN, "in"); // 初始化为输入模式
                log("GPIO初始化成功");
            } catch (IOException e) {
                log("GPIO初始化失败: " + e.getMessage());
                Log.e(TAG, "GPIO初始化失败", e);
            }
        }

        // 启动接收线程
        public void startListening() {
            if (isRunning) return;
            isRunning = true;

            receiveThread = new Thread(() -> {
                log("开始监听主机数据...");
                while (isRunning) {
                    try {
                        // 1. 检测引导码(2ms低电平)
                        if (detectLeaderCode()) {
                            log("检测到引导码");
                            // 2. 接收数据包
                            byte[] packet = receivePacket();
                            if (validatePacket(packet)) {
                                log("数据包校验成功");
                                // 3. 提取显示数据(跳过引导码和校验码)
                                byte[] displayData = new byte[5];
                                System.arraycopy(packet, 1, displayData, 0, 5);
                                listener.onDisplayData(displayData);
                            } else {
                                log("数据包校验失败");
                            }
                        }
                    } catch (IOException e) {
                        log("通信异常: " + e.getMessage());
                        Log.e(TAG, "通信异常", e);
                    }
                }
            });
            receiveThread.start();
        }

        // 检测引导码(2ms低电平)
        private boolean detectLeaderCode() throws IOException {
            long startTime = System.currentTimeMillis();
            while (readGPIO(DATA_PIN) == 1) { // 等待低电平
                if (System.currentTimeMillis() - startTime > 10) return false;
            }

            // 测量低电平持续时间
            long lowStart = System.currentTimeMillis();
            while (readGPIO(DATA_PIN) == 0) {} // 等待变高
            long duration = System.currentTimeMillis() - lowStart;

            return duration >= LEADER_CODE_DURATION; // 持续时间≥2ms
        }

        // 接收完整数据包
        private byte[] receivePacket() throws IOException {
            byte[] packet = new byte[PACKET_SIZE];

            for (int i = 0; i < PACKET_SIZE; i++) {
                packet[i] = receiveByte();
                log("收到字节[" + i + "]: 0x" + String.format("%02X", packet[i]));
            }
            return packet;
        }

        // 接收单字节
        private byte receiveByte() throws IOException {
            byte value = 0;
            for (int i = 0; i < 8; i++) {
                // 等待上升沿
                while (readGPIO(DATA_PIN) == 0) {}

                // 测量高电平时间
                long highStart = System.nanoTime();
                while (readGPIO(DATA_PIN) == 1) {}
                long highDuration = (System.nanoTime() - highStart) / 1000; // 转为微秒

                // 根据高电平时间判断位值(1码:500μs, 0码:125μs)
                if (highDuration > 350) { // 350-650μs视为1
                    value |= (1 << i); // LSB first
                    log("收到位[" + i + "]: 1 (" + highDuration + "μs)");
                } else {
                    log("收到位[" + i + "]: 0 (" + highDuration + "μs)");
                }
                // 等待位结束
                delayMicros(BIT_DELAY - highDuration);
            }
            return value;
        }

        // 发送按键数据
        public void sendKeyValue(byte keyValue) {
            new Thread(() -> {
                try {
                    log("开始发送按键: 0x" + String.format("%02X", keyValue));
                    setGPIODirection(DATA_PIN, "out");

                    // 1. 发送引导码(2ms低电平)
                    writeGPIO(DATA_PIN, 0);
                    delayMicros(LEADER_CODE_DURATION * 1000);
                    log("发送引导码完成");

                    // 2. 发送数据码
                    sendByte(keyValue);
                    log("发送数据码完成");

                    // 3. 发送校验码(数据码取反)
                    byte checksum = (byte) ~keyValue;
                    sendByte(checksum);
                    log("发送校验码完成: 0x" + String.format("%02X", checksum));

                    // 恢复高电平
                    writeGPIO(DATA_PIN, 1);
                    setGPIODirection(DATA_PIN, "in");

                    listener.onSendComplete();
                } catch (IOException e) {
                    log("发送失败: " + e.getMessage());
                    Log.e(TAG, "发送失败", e);
                }
            }).start();
        }

        // 发送单字节
        private void sendByte(byte data) throws IOException {
            for (int i = 0; i < 8; i++) {
                boolean bit = ((data >> i) & 1) == 1; // LSB first

                if (bit) {
                    // 1码: 500μs高电平+250μs低电平
                    writeGPIO(DATA_PIN, 1);
                    delayMicros(500);
                    writeGPIO(DATA_PIN, 0);
                    delayMicros(250);
                    log("发送位[" + i + "]: 1");
                } else {
                    // 0码: 125μs高电平+625μs低电平
                    writeGPIO(DATA_PIN, 1);
                    delayMicros(125);
                    writeGPIO(DATA_PIN, 0);
                    delayMicros(625);
                    log("发送位[" + i + "]: 0");
                }
            }
        }

        // 数据包校验
        private boolean validatePacket(byte[] packet) {
            // 检查识别码
            if (packet[0] != IDENTIFICATION_CODE) {
                log("识别码错误: 期望0xA5, 实际0x" + String.format("%02X", packet[0]));
                return false;
            }

            // 计算校验和(1~6字节)
            byte checksum = 0;
            for (int i = 0; i < PACKET_SIZE - 1; i++) {
                checksum += packet[i];
            }

            boolean valid = checksum == packet[PACKET_SIZE - 1];
            if (!valid) {
                log("校验失败: 计算值0x" + String.format("%02X", checksum) +
                        ", 实际值0x" + String.format("%02X", packet[PACKET_SIZE - 1]));
            }
            return valid;
        }

        // GPIO底层操作
        private void exportGPIO(int pin) throws IOException {
            File exportFile = new File(GPIO_BASE + "/export");
            writeFile(exportFile, String.valueOf(pin));
        }

        private void setGPIODirection(int pin, String direction) throws IOException {
            File dirFile = new File(GPIO_BASE + "/gpio" + pin + "/direction");
            writeFile(dirFile, direction);
        }

        private void writeGPIO(int pin, int value) throws IOException {
            File valueFile = new File(GPIO_BASE + "/gpio" + pin + "/value");
            writeFile(valueFile, String.valueOf(value));
        }

        private int readGPIO(int pin) throws IOException {
            // 实际实现需要读取/sys/class/gpio/gpioX/value
            // 这里为简化示例，实际项目中需要实现
            return 0;
        }

        private void writeFile(File file, String value) throws IOException {
            try (FileOutputStream fos = new FileOutputStream(file)) {
                fos.write(value.getBytes());
            }
        }

        private void delayMicros(long micros) {
            try {
                Thread.sleep(0, (int)(micros * 1000));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

        private void log(String message) {
            if (listener != null) {
                listener.onLogMessage(message);
            }
        }

        public void release() {
            isRunning = false;
            if (receiveThread != null) {
                receiveThread.interrupt();
            }
            log("通信模块已释放");
        }


}
